package com.caozhi.mspeoject.nb_message.controller.admin;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.caozhi.mspeoject.nb_message.mapper.MessageMapper;
import com.caozhi.mspeoject.nb_message.remote.DistributedId;
import com.caozhi.mspeoject.nb_message.remote.EsMessageRemote;
import com.caozhi.mspeoject.nb_message.service.admin.AdminMediaService;
import com.caozhi.mspeoject.nb_message.service.admin.AdminMessageService;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.woniuxy.boot.common.bean.EsMessage;
import com.woniuxy.boot.common.bean.Media;
import com.woniuxy.boot.common.bean.Message;
import com.woniuxy.boot.common.dto.EsMessageDTO;
import com.woniuxy.boot.common.pojo.ResponseResult;
import com.woniuxy.boot.common.util.EntityConverter;
import com.woniuxy.boot.common.vo.MessageVO;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@RestController("admin")
@RequestMapping("admin/message")
public class MessageController {
    @Autowired
    private AdminMessageService adminMessageService;
    @Autowired
    private EsMessageRemote esMessageRemote;
    @Autowired
    private MessageMapper messageMapper;
    @Autowired
    private AdminMediaService adminMediaService;
    @Autowired
    private DistributedId distributedId;
    @Autowired
    private RedisTemplate redisTemplate;


    @GetMapping("get")
    public List<Message> getMessages() {
        return adminMessageService.getEsMessages();
    }

    @PostMapping("addMessage")
    public ResponseResult<Void> addMessage(@RequestBody MessageVO messageVO) {
        Message message = EntityConverter.convert(messageVO, Message.class);
        Long MessageId = distributedId.getDistributeID();

        message.setId(MessageId);
        message.setCommitTime(LocalDateTime.now());
        message.setNo(UUID.randomUUID().toString());
        messageMapper.insert(message);
        messageVO.getMediaList().forEach(media -> {
            media.setId(distributedId.getDistributeID());
            media.setMessageId(MessageId);
            adminMediaService.addMedia(media);
        });
        return ResponseResult.SUCCESS;
    }

    @PostMapping("searchMessage")
    public List<EsMessage> searchMessage(@RequestBody EsMessageDTO esMessageDTO) {
        List<EsMessage> esMessages = esMessageRemote.getMessages(esMessageDTO);
        if (esMessages.isEmpty()) {
            QueryWrapper<Message> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("title", esMessageDTO.getKeyword()).or().eq("no", esMessageDTO.getKeyword());
            List<Message> messages = adminMessageService.getMessagesByConditon(queryWrapper);
            List<EsMessage> finalEsMessages = new ArrayList<>(esMessages);
            messages.forEach(message -> {
                EsMessage esMessage = EntityConverter.convert(message, EsMessage.class);
                List<Media> medias = adminMediaService.getMediaByMessageId(message.getId());
                if (medias != null && !medias.isEmpty()) {
                    esMessage.setMediaList(medias);
                }
                finalEsMessages.add(esMessage);
            });
            esMessages = finalEsMessages;
        }
        esMessages = filterByCommitTime(esMessages, esMessageDTO);
        esMessages = filterByDownTime(esMessages, esMessageDTO);

        if (esMessageDTO.getIdRecommend() != null) {
            esMessages = esMessages.stream()
                    .filter(e -> e.getRecommend().equals(esMessageDTO.getIdRecommend()))
                    .collect(Collectors.toList());
        }
        return esMessages;
    }
    private List<EsMessage> filterByCommitTime(List<EsMessage> esMessages, EsMessageDTO esMessageDTO) {
        if (esMessageDTO.getCommitTime() != null && esMessageDTO.getNextCommitTime() != null) {
            return esMessages.stream()
                    .filter(e -> e.getCommitTime().isAfter(esMessageDTO.getCommitTime()) && e.getCommitTime().isBefore(esMessageDTO.getNextCommitTime()))
                    .collect(Collectors.toList());
        } else if (esMessageDTO.getCommitTime() != null) {
            return esMessages.stream()
                    .filter(e -> e.getCommitTime().isAfter(esMessageDTO.getCommitTime()))
                    .collect(Collectors.toList());
        } else if (esMessageDTO.getNextCommitTime() != null) {
            return esMessages.stream()
                    .filter(e -> e.getCommitTime().isBefore(esMessageDTO.getNextCommitTime()))
                    .collect(Collectors.toList());
        }
        return esMessages;
    }
    private List<EsMessage> filterByDownTime(List<EsMessage> esMessages, EsMessageDTO esMessageDTO) {
        if (esMessageDTO.getDownTime() != null && esMessageDTO.getNextDownTime() != null) {
            return esMessages.stream()
                    .filter(e -> e.getDownTime().isAfter(esMessageDTO.getDownTime()) && e.getDownTime().isBefore(esMessageDTO.getNextDownTime()))
                    .collect(Collectors.toList());
        } else if (esMessageDTO.getDownTime() != null) {
            return esMessages.stream()
                    .filter(e -> e.getDownTime().isAfter(esMessageDTO.getDownTime()))
                    .collect(Collectors.toList());
        } else if (esMessageDTO.getNextDownTime() != null) {
            return esMessages.stream()
                    .filter(e -> e.getDownTime().isBefore(esMessageDTO.getNextDownTime()))
                    .collect(Collectors.toList());
        }
        return esMessages;
    }


    @PostMapping("update")
    @Transactional
    public ResponseResult<Void> updateMessage(@RequestBody Message message) {
        if (message.getRecommend() != null) {
            handleRecommendUpdate(message);
        }
        LambdaUpdateWrapper<Message> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(Message::getId, message.getId());

        if (message.getArticleCategoryId() != null) {
            lambdaUpdateWrapper.set(Message::getArticleCategoryId, message.getArticleCategoryId());
        }
        lambdaUpdateWrapper.set(Message::getLastChangetime, LocalDateTime.now());

        int rowsAffected = messageMapper.update(null, lambdaUpdateWrapper);
        if (rowsAffected > 0) {
            synchronizedRedis();
        }
        return ResponseResult.SUCCESS;
    }
    private void handleRecommendUpdate(Message message) {
        if ("a".equals(message.getRecommend())) {
            QueryWrapper<Message> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("recommend", "a");
            Long count = messageMapper.selectCount(queryWrapper);
            if (count >= 5L) {
                List<Message> messages = messageMapper.selectList(queryWrapper);
                messages.sort(Comparator.comparing(Message::getLastChangetime));

                // 更新最早的一条记录的状态为 "b"
                Message oldestMessage = messages.get(0);
                UpdateWrapper<Message> updateWrapper = new UpdateWrapper<>();
                updateWrapper.eq("id", oldestMessage.getId())
                        .set("recommend", "b")
                        .set("last_changetime", LocalDateTime.now());
                messageMapper.update(updateWrapper);
                UpdateWrapper<Message> updateWrapper2 = new UpdateWrapper<>();
                updateWrapper2.eq("id", message.getId());
                updateWrapper2.eq("recommend", "a");
                messageMapper.update(updateWrapper2);

            } else {
                UpdateWrapper<Message> updateWrapper = new UpdateWrapper<>();
                updateWrapper.eq("id", message.getId())
                        .set("recommend", "a")
                        .set("last_changetime", LocalDateTime.now());
                messageMapper.update(updateWrapper);
            }
        } else {
            UpdateWrapper<Message> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("id", message.getId())
                    .set("recommend", "b")
                    .set("last_changetime", LocalDateTime.now());
            messageMapper.update(updateWrapper);
        }
    }

    private synchronized void synchronizedRedis() {
        try {
            QueryWrapper<Message> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("recommend", "a");
            List<Message> messages = adminMessageService.getMessagesByConditon(queryWrapper);

            ValueOperations<Integer, List<Message>> valueOperations = redisTemplate.opsForValue();
            redisTemplate.delete("recommend");

            ObjectMapper objectMapper = new ObjectMapper();
            valueOperations.set(1, messages);
        } catch (Exception e) {
            throw new RuntimeException("Failed to synchronize Redis", e);
        }
    }

}
